package com.gkzf.ai.module.crm.util;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 生成二维码
 * @author Huawei
 * @date 2025-04-18 14:11
 */
public class QRCodeGenerator {
    /**
     * 生成二维码
     * @param reqUrl 跳转的路径
     * @param filePath 图片名称
     * @param width 图片长
     * @param height 图片宽
     * @throws Exception
     */

    public static byte[] generateQRCodeImage(String reqUrl, int width, int height){
        Map<EncodeHintType, Object> hintMap = new HashMap<>();
        hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix = null;
        try {
            bitMatrix = qrCodeWriter.encode(reqUrl, BarcodeFormat.QR_CODE, width, height, hintMap);
        } catch (WriterException e) {
            throw new RuntimeException(e);
        }

        ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream();
        try {
            MatrixToImageWriter.writeToStream(bitMatrix, "PNG", pngOutputStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return pngOutputStream.toByteArray();
    }


    /**
     * 生成带图片的二维码
     * @param reqUrl URL 或文本内容
     * @param width 图片宽度
     * @param height 图片高度
     * @param logoInputStream Logo 图片的输入流 (例如: FileInputStream, ClassPathResource.getInputStream())
     * @param logoPercentage Logo 相对于二维码尺寸的比例 (建议值 0.1f - 0.2f, 例如 0.15f 表示 Logo 边长是二维码边长的 15%)
     * @return 包含二维码和 Logo 的 PNG 图片的 byte 数组
     * @throws RuntimeException 如果生成或处理图片失败
     */
    public static byte[] generateQRCodeImageWithLogo(String reqUrl, int width, int height, InputStream logoInputStream, float logoPercentage) {
        Objects.requireNonNull(reqUrl, "reqUrl cannot be null");
        Objects.requireNonNull(logoInputStream, "logoInputStream cannot be null");
        if (width <= 0 || height <= 0) {
            throw new IllegalArgumentException("Width and height must be positive");
        }
        if (logoPercentage <= 0 || logoPercentage >= 1) {
            throw new IllegalArgumentException("logoPercentage must be between 0 and 1 (exclusive)");
        }

        // 1. 生成基础二维码 BitMatrix
        Map<EncodeHintType, Object> hintMap = new HashMap<>();
        // 重要的改变：带 Logo 通常需要更高的纠错等级 (H 级别可以容忍约 30% 的损坏)
        hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hintMap.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 指定字符集，防止内容有中文乱码

        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix;
        try {
            bitMatrix = qrCodeWriter.encode(reqUrl, BarcodeFormat.QR_CODE, width, height, hintMap);
        } catch (WriterException e) {
            throw new RuntimeException("Failed to encode QR code", e);
        }

        // 2. 将 BitMatrix 转换为 BufferedImage (黑白二维码基础图)
        // 使用默认的 MatrixToImageWriter 转换为 BufferedImage (通常是黑白)
        BufferedImage qrImage;
        try {
            // 这里可以使用 MatrixToImageWriter.toBufferedImage(bitMatrix)
            // 或者为了确保一致的颜色，手动指定黑白色：
            MatrixToImageConfig config = new MatrixToImageConfig(0xFF000000, 0xFFFFFFFF); // 黑点，白背景
            qrImage = MatrixToImageWriter.toBufferedImage(bitMatrix, config);
        } catch (Exception e) {
            // MatrixToImageWriter.toBufferedImage 实际上不抛出 WriterException，但以防万一捕获一下
            throw new RuntimeException("Failed to convert BitMatrix to BufferedImage", e);
        }


        // 3. 读取 Logo 图片
        BufferedImage logoImage;
        try {
            logoImage = ImageIO.read(logoInputStream);
        } catch (IOException e) {
            throw new RuntimeException("Failed to read logo image from stream", e);
        }
        if (logoImage == null) {
            // ImageIO.read 如果无法解析格式或流是空的/无效的，会返回 null
            throw new RuntimeException("Could not decode logo image from input stream. Invalid format or empty stream?");
        }

        // 4. 创建一个新的支持颜色的 BufferedImage 作为最终画布
        int qrWidth = qrImage.getWidth();
        int qrHeight = qrImage.getHeight();
        // 使用 TYPE_INT_ARGB，这是最常用的支持透明度和全彩的 BufferedImage 类型
        BufferedImage finalImage = new BufferedImage(qrWidth, qrHeight, BufferedImage.TYPE_INT_ARGB);

        // 获取新的 Graphics2D 对象，用于绘制到 finalImage
        Graphics2D graphics = finalImage.createGraphics();

        // 将原始的黑白二维码绘制到新的彩色画布上
        graphics.drawImage(qrImage, 0, 0, qrWidth, qrHeight, null);


        // 5. 计算 Logo 的位置和尺寸 (同原代码)
        int logoTargetSize = (int) (qrWidth * logoPercentage);
        // 确保 Logo 尺寸至少为 1 像素
        if (logoTargetSize <= 0) {
            logoTargetSize = Math.min(qrWidth, qrHeight) / 5;
            if (logoTargetSize <= 0) logoTargetSize = 1;
        }

        // 计算 Logo 在二维码中心的位置
        int logoX = (qrWidth - logoTargetSize) / 2;
        int logoY = (qrHeight - logoTargetSize) / 2;

        // (可选但推荐) 为 Logo 添加白色边框
        int borderSize = (int) (logoTargetSize * 0.1);
        int borderedLogoSize = logoTargetSize + 2 * borderSize;
        int borderedLogoX = (qrWidth - borderedLogoSize) / 2;
        int borderedLogoY = (qrHeight - borderedLogoSize) / 2;


        // 6. 将 Logo 绘制到新的彩色画布上
        // 设置渲染参数以获得更好的图像质量（可选）
        graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // 绘制 Logo 的白色边框 (绘制到 finalImage 上)
        graphics.setColor(Color.WHITE); // 需要 java.awt.Color
        graphics.fillRect(borderedLogoX, borderedLogoY, borderedLogoSize, borderedLogoSize);

        // 绘制 Logo 图片 (绘制到 finalImage 上)，它会保留自己的颜色
        graphics.drawImage(logoImage, logoX, logoY, logoTargetSize, logoTargetSize, null); // 将 logoImage 缩放到 targetSize 绘制到指定位置


        // 7. 释放图形上下文资源
        graphics.dispose();

        // 8. 将合并后的 finalImage (彩色) 转换为 byte[]
        ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream();
        try {
            ImageIO.write(finalImage, "PNG", pngOutputStream); // 将新的彩色图片写入流
        } catch (IOException e) {
            throw new RuntimeException("Failed to write combined QR code image to stream", e);
        }

        return pngOutputStream.toByteArray();
    }

    /**
     * 下载远程图片并返回其内容作为 InputStream。
     * 调用者有责任关闭返回的 InputStream。
     *
     * @param imageUrl 远程图片的 URL 地址
     * @return 图片内容的 InputStream
     * @throws IOException 如果下载过程中发生网络错误、URL 无效或 HTTP 响应非 200
     * @throws IllegalArgumentException 如果 URL 字符串格式错误
     */
    public static InputStream downloadImageFromUrl(String imageUrl){
        if (imageUrl == null || imageUrl.trim().isEmpty()) {
            throw new IllegalArgumentException("Image URL cannot be null or empty");
        }

        URL url;
        try {
            url = new URL(imageUrl);
        } catch (MalformedURLException e) {
            throw new IllegalArgumentException("Invalid image URL format: " + imageUrl, e);
        }

        HttpURLConnection conn = null; // 使用 HttpURLConnection 来处理 HTTP/HTTPS
        try {
            // 打开连接
            conn = (HttpURLConnection) url.openConnection();

            // 设置请求方法为 GET
            conn.setRequestMethod("GET");

            // 设置连接超时和读取超时 (单位: 毫秒)
            conn.setConnectTimeout(5000); // 连接超时 5 秒
            conn.setReadTimeout(10000);  // 读取超时 10 秒

            // 允许重定向
            conn.setInstanceFollowRedirects(true);

            // 连接到 URL
            conn.connect();

            // 检查 HTTP 响应码
            int responseCode = conn.getResponseCode();
            if (responseCode != HttpURLConnection.HTTP_OK) { // 200 OK
                // 如果响应不是 200 OK，说明下载失败
                // 尝试获取错误流并关闭连接
                try {
                    // 尝试读取错误流以获取更多信息 (可选)
                    InputStream errorStream = conn.getErrorStream();
                    if (errorStream != null) {
                        // 可以选择读取 errorStream 的内容，但通常对于图片下载失败不常用
                        errorStream.close();
                    }
                } finally {
                    // 确保连接关闭
                    conn.disconnect();
                }
                throw new IOException("Failed to download image from " + imageUrl + ". HTTP error code: " + responseCode);
            }

            // 获取输入流
            // 注意：这个 InputStream 是直接从网络连接读取的。
            // 调用者（即调用 ImageIO.read 的地方）负责读取和关闭这个流。
            // 当这个流被关闭时，底层的网络资源（连接）也会被适当地释放。
            return conn.getInputStream();

        } catch (IOException e) {
            // 捕获所有其他的 IO 异常（如网络不可达等）
            // 如果连接已经建立，确保断开连接
            if (conn != null) {
                conn.disconnect();
            }
        }
        // finally {
        //    // 注意：这里不能直接 conn.disconnect()，因为返回的 InputStream 可能还在使用连接
        //    // 连接的管理通常由返回的 InputStream 的生命周期决定，特别是当它被关闭时。
        // }
        return null;
    }

    public static void main(String[] args) {
        try {
            InputStream inputStream = downloadImageFromUrl("https://baizeyunxi.tos-cn-beijing.volces.com/325a866926f5c2d68cd0ee34dbac3ea76481ebc43d6233892fafce43bdad6e8a.jpg");
            generateQRCodeImageWithLogo("http://121.37.187.242:8091/?creditBasicId=1",  300, 300, inputStream,0.2f);
            System.out.println("二维码生成成功！");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
